/*  Classe che implementa delle funzionalità utili alla gestione del DOM    */

package sybel;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author Stefano
 */
public class DomBuilder {

    private String[] tags = {
        "behaviour",
        "attributes",
        "parameters",
        "preconditions",
        "postconditions",
        "flow",
        "trigger",
        "interaction",
        "happening",
        "alternative",
        "include"
    };

    public static Document newDocument(){
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        /* Si impostano le caratteristiche desiderate per il DOM */
        //factory.setValidating(false);
        factory.setNamespaceAware(true);
        try {
            factory.setAttribute("http://dellapenna.univaq.it/sdml/behaviour", "SDML3_behaviour.xsd");
        }
        catch (IllegalArgumentException e) {
            System.err.println("could not set parser property");
        }
        DocumentBuilder d;

        try{
            d = factory.newDocumentBuilder();
            Document doc = d.newDocument();
            return doc;
        }catch(ParserConfigurationException pce){
            return null;
        }
    }

    
/**
 * Metodo che inizializza e crea un nuovo behaviour
 *
 * @param name nome del behaviour
 * @param domain dominio del behaviour
 * @param ID
 */
    public static Document newBehaviourDocument(String name,String domain,String ID){
        Document behaviour = newDocument();
        Element radice = behaviour.createElement("behaviour");
        
        //------ settaggio namespaces URI e schemalocation ----------
        //radice.setAttribute("xsi:schemaLocation=","http://dellapenna.univaq.it/sdml/behaviour SDML3_behaviour.xsd");
        radice.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
        radice.setAttribute("xmlns","http://dellapenna.univaq.it/sdml/behaviour");

        Element attribute = behaviour.createElement("attributes");
        Element parameters = behaviour.createElement("parameters");
        Element trigger = behaviour.createElement("trigger");
        Element flow =   behaviour.createElement("flow");
        try{
            radice.setAttribute("name", name);
            radice.setAttribute("domain", domain);
            if(!ID.isEmpty())
                radice.setAttribute("id", ID);
        }catch (DOMException dex){
            JOptionPane.showMessageDialog(null, "ERRORE: "+dex.getMessage(),"An error has occured" ,1);
            return null;
        }
        radice.appendChild(attribute);
        radice.appendChild(parameters);
        radice.appendChild(trigger);
        radice.appendChild(flow);
        behaviour.appendChild(radice);
        return behaviour;
    }

/**
 * Metodo che crea un elemento del flow 
 *
 * @param event intero che rappresenta il nodo da aggiungere
 * @param doc il documento a cui và aggiunto il nodo
 * @return
 */
public static Document newFlowChild(int event, Document doc){
    Element flowchild = null;
    try{
        switch(event){
        // new Interaction
        case 0:
            flowchild = doc.createElement("interaction");
            break;
        // new Happening
        case 1:
            flowchild = doc.createElement("happening");
            break;
        // new Alternative
        case 2:
            flowchild = doc.createElement("alternative");
            break;
        // new Include
        case 3:
            flowchild = doc.createElement("include");
            break;
        }
    // appendo l'elemento creato come ultimo figlio dell'ultimo nodo "flow"
    doc.getFirstChild().getLastChild().appendChild(flowchild);
    }catch (DOMException dex){
        JOptionPane.showMessageDialog(null, "ERRORE: "+dex.getMessage(),"An error has occured" ,1);
        return null;
    }
    return doc;
    }

/**
 * Metodo che aggiunge al behaviour le preconditions o postconditions, a seconda di quale delle due
 * si richiedono tramite il parametro condition
 *
 * @param condition è la stringa che identifica e distingue "preconditions" da "postconditions"
 * @param doc il DOM al quale và aggiunta la condizione
 * @return il dom con il nuovo nodo
 */
public static Document addPrePostconditions(String condition,Document doc){
    if(doc.getElementsByTagName(condition).item(0) != null){
        JOptionPane.showMessageDialog(null, condition +" already exist in this behaviour" );
        return null;
    }

    Element cond = doc.createElement(condition);
    if(condition == "preconditions"){
        Node postcond = doc.getElementsByTagName("postconditions").item(0);
        if(postcond != null)
            doc.getFirstChild().insertBefore(cond, postcond);
        else
            doc.getFirstChild().insertBefore(cond, doc.getElementsByTagName("trigger").item(0));
    }else{
        doc.getFirstChild().insertBefore(cond, doc.getElementsByTagName("trigger").item(0));
    }

    return doc;
}

/**
 * Restituisce true se è presente l'elemento attributes nel documento, false altrimenti
 *
 * @param doc il DOM da esaminare
 * @return true se "attributes" è presente, false altrimenti
 */
public static boolean hasAttributes(Document doc){
    NodeList attr = doc.getElementsByTagName("attributes");
    if(attr.getLength()==0){
        return false;
    }
    return true;
}

/**
 * Metodo che indica se è specificato o meno l'interactive actor nel documento
 *
 * @param doc il documento xml
 * @return true se è specificato l'interactive actor
 * @return false se l'interactive actor non è specificato
 */
public static boolean hasInteractiveActor(Document doc){
    NodeList nl = doc.getElementsByTagName("interactiveActor");
    if(nl.getLength() > 0)
        return true;
    return false;
}

/**
 * Metodo che indica se è specificato o meno il system actor nel documento
 *
 * @param doc il documento xml
 * @return true se è specificato il system actor
 * @return false se l'interactive actor non è specificato
 */
public static boolean hasSystemActor(Document doc){
    NodeList nl = doc.getElementsByTagName("systemActor");
    if(nl.getLength() > 0)
        return true;
    return false;
}

    /**
     *Metodo che restituisce la stringa contenente l'interactive Actor
     *
     * @return interactiveActor oppure null se questo non è specificato nel documento
     */
    public static String getInteractiveActor(Document doc){
        String s= null;
        NodeList childnodes = doc.getChildNodes();
        for(int i=0; i < childnodes.getLength(); i++){
            Node n = childnodes.item(i);
            if(n.getNodeName()== "interactiveActor")
                return n.getTextContent();
        }
        return s;
    }

    /**
     *Metodo che restituisce la stringa contenente il systemActor
     *
     * @return systemActor oppure null se questo non è specificato nel documento
     */
    public static String getSystemActor(Document doc){
        String s= null;
        NodeList childnodes = doc.getChildNodes();
        for(int i=0; i < childnodes.getLength(); i++){
            Node n = childnodes.item(i);
            if(n.getNodeName()== "systemActor")
                return n.getTextContent();
        }
        return s;
    }
}
